package com.apobates.forum.toro.proxy;

import com.apobates.forum.toro.BatchQueryFace;
import com.apobates.forum.toro.core.BeanParser;
import com.apobates.forum.toro.core.Corner;
import com.apobates.forum.toro.core.Express;
import com.apobates.forum.toro.core.TypeEnum;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 聚合属性语句
 * 适用于: 多对多
 *
 * @author xiaofanku@live.cn
 * @since 20220517
 */
public class MapperMultiAttrStatements{
    /**
     * 查询表达式集合
     */
    private Set<MapperMultiAttrExpression> selectSet;
    private final static BeanParser<MapperMultiAttrStatements.Argument> parser;
    static {
        // targetAttr:collectionType=select(selectAttr)&filter(joinAttr:joinAttrTypeName)
        Express exp = Express.getInstance()
                .word("targetAttr")
                .corner(Corner.sequence(0).edge(":").build())
                .word("collectionType")
                .corner(Corner.sequence(1).require(false).give("bean").edge("=select(").build())
                .word("selectAttr")
                .corner(Corner.sequence(2).edge(")&filter(").build())
                .word("joinAttr")
                .corner(Corner.sequence(3).edge(":").build())
                .word("joinAttrTypeName")
                .corner(Corner.sequence(4).require(false).give("long").type(TypeEnum.Str).edge(")").build());
        // 从表达式到实例
        parser = exp.build(MapperMultiAttrStatements.Argument.class);
    }
    /**
     * MapperMultiAttrStatements构造函数
     */
    public MapperMultiAttrStatements() {
        this.selectSet = new HashSet<>();
    }

    /**
     * MapperMultiAttrStatements构造函数
     * @param selectSet
     */
    private MapperMultiAttrStatements(Set<MapperMultiAttrExpression> selectSet) {
        this.selectSet = selectSet;
    }

    /**
     * 设置目标对象的属性名称.
     * 通过Argument构造者设置关联属性。注意：不要与expr混用
     *
     * @param targetAttr 目标对象的属性名称
     * @return 属性表达式语句构建器
     */
    public Argument attr(String targetAttr) {
        return new Argument(targetAttr);
    }

    /*
     * 设置参数语句表达式描述
     * 通过描述字符串设置关联属性。注意：不要与attr混用
     * 格式: targetAttr=select(selectAttr:selectAttrTypeName)&filter(joinAttr:joinAttrTypeName)
     * @param exprDescribe 查询参数表达式描述
     * @return
     *
    @Override
    public Argument expr(String exprDescribe) {
        ArgumentExprDescribeParser ap = new ArgumentExprDescribeParser(exprDescribe, MapperMultiAttrStatements.Argument.class);
        Map<String,String> argMap = ap.parse(MULTI_FORMAT, MULTI);
        return new Argument(argMap.get("targetAttr"))
                .used(argMap.get("selectAttr"))
                .usedType(argMap.get("selectAttrTypeName"))
                .join(argMap.get("joinAttr"))
                .joinType(argMap.get("joinAttrTypeName"))
                .collection(argMap.get("collectionType"));
    }*/

    /**
     * 设置参数语句表达式描述
     * 通过描述字符串设置关联属性。注意：不要与attr混用
     * 格式: targetAttr:collectionType=select(selectAttr)&filter(joinAttr:joinAttrTypeName)
     * @param exprDescribe 查询参数表达式描述
     * @return
     */
    public Argument expr(String exprDescribe) {
        // targetAttr:collectionType=select(selectAttr)&filter(joinAttr:joinAttrTypeName)
        Map<String,Object> argMap = parser.toMap(exprDescribe);
        return new Argument(argMap.get("targetAttr").toString())
                .collection(argMap.get("collectionType").toString())
                .used(argMap.get("selectAttr").toString())
                .join(argMap.get("joinAttr").toString())
                .joinType(argMap.get("joinAttrTypeName").toString());
    }

    public Set<MapperMultiAttrExpression> getSelectMap() {
        return selectSet;
    }

    /**
     * 聚合属性语句构建器
     */
    public class Argument {
        /**
         * 要设置Vo哪个属性
         * 例:Vo.topic
         */
        private final String targetAttr;
        /**
         * 集合的类型
         */
        private String collectionType;
        /**
         * 使用参数的哪个属性的的值作为Select参数
         * 例: Vo.topicId
         */
        private String selectAttr;
        /**
         * selectAttr的类型名称
         * 例: 基础类型: long, 类类型: java.lang.Long
         */
        private String selectAttrTypeName;
        /**
         * 关联聚合对象使用的连接属性
         * 例: selectObj.id( = Vo.topicId)
         */
        private String joinAttr;
        /**
         * 关联聚合对象使用的连接属性类型
         * 例: 基础类型: long, 类类型: java.lang.Long
         */
        private String joinAttrTypeName;


        /**
         * 构造器的构造函数
         * @param targetAttr 目标属性名称
         */
        public Argument(String targetAttr) {
            this.joinAttrTypeName = "long";
            this.joinAttr = "id";
            this.targetAttr = targetAttr;
            this.collectionType = "bean";
        }

        public Argument collection(String targetCollectionType){
            this.collectionType = targetCollectionType;
            return this;
        }
        /**
         * 设置查询参数的属性名称. 通常是对象的关联属性
         * @param selectAttr 查询参数的属性名称
         * @return 返回构造器
         */
        public Argument used(String selectAttr){
            this.selectAttr = selectAttr;
            return this;
        }
        /**
         * 设置查询参数的类型名称. 通常是对象的关联属性
         * 例: 基础类型: long, 类类型: java.lang.Long
         *
         * @param selectAttrTypeName
         * @return
         */
        public Argument usedType(String selectAttrTypeName){
            this.selectAttrTypeName = selectAttrTypeName;
            return this;
        }

        /**
         * 设置查询参数的类型名称. 通常是对象的关联属性
         * 使用内置的类型枚举.只支持String和8种基础类型及其包装类
         *
         * @param selectAttrType
         * @return
         */
        public Argument usedType(TypeEnum selectAttrType){
            this.selectAttrTypeName = selectAttrType.getType();
            return this;
        }
        /**
         * 设置关联聚合对象使用的连接属性
         * @param relationAttr
         * @return
         */
        public Argument join(String relationAttr){
            this.joinAttr = relationAttr;
            return this;
        }

        /**
         * 设置关联聚合对象使用的连接属性类型
         * 例: 基础类型: long, 类类型: java.lang.Long
         * @param joinAttrTypeName
         * @return
         */
        public Argument joinType(String joinAttrTypeName){
            this.joinAttrTypeName = joinAttrTypeName;
            if(null == this.selectAttrTypeName){
                this.selectAttrTypeName = joinAttrTypeName;
            }
            return this;
        }

        /**
         * 设置关联聚合对象使用的连接属性类型
         * 使用内置的类型枚举.只支持String和8种基础类型及其包装类
         * @param joinAttrType
         * @return
         */
        public Argument joinType(TypeEnum joinAttrType){
            this.joinAttrTypeName = joinAttrType.getType();
            return this;
        }
        public String getTargetAttr() {
            return targetAttr;
        }

        public String getSelectAttr() {
            return selectAttr;
        }

        public String getJoinAttr() {
            return joinAttr;
        }

        public String getJoinAttrTypeName() {
            return joinAttrTypeName;
        }

        public String getSelectAttrTypeName() {
            return selectAttrTypeName;
        }

        public String getCollectionType() {
            return collectionType;
        }

        /**
         * 设置目标对象属性值的批量查询接口
         * @param queryFace 批量查询接口
         * @return 聚合属性表达式
         * @param <R> 查询函数的返回值类型
         */
        public <R> MapperMultiAttrStatements select(BatchQueryFace<R> queryFace) {
            MapperMultiAttrExpression maq = new MapperMultiAttrExpression(
                    this.targetAttr,
                    this.collectionType,
                    this.selectAttr,
                    this.selectAttrTypeName,
                    this.joinAttr,
                    this.joinAttrTypeName,
                    queryFace);
            getSelectMap().add(maq);
            return new MapperMultiAttrStatements(getSelectMap());
        }

        public boolean isTargetAttrSet(){
            return null !=this.collectionType && this.collectionType.startsWith("java.util.");
        }
    }
}
